//
//  TBBLEManager.m
//  TBSDK
//
//  Created by nexgo on 2017/9/29.
//  Copyright © 2017年 truth. All rights reserved.
//

#import "TBBLEManager.h"

@interface TBBLEManager()<CBCentralManagerDelegate>{
    CBCentralManager* cbCentralManager;
    
    BOOL scaning;
    
    TBBLEScanMode scanMode;
    NSArray<CBUUID *>* uuids;
    TBBLEScanCB* scanCB;
    int workTime;
    int sleepTime;
    int workTimes;
    
    NSMutableArray<TBBLEDevice*>* devices;
    
    NSMutableDictionary* connectCBMap;
    
    NSMutableDictionary* disconnectFlagMap;
}
@end

@implementation TBBLEManager
static TBBLEManager* manager;

/**
 单例
 @return 单例
 */
+(instancetype)getInstance{
    if(manager == nil){
        manager = [[TBBLEManager alloc] init];
    }
    return manager;
}

- (instancetype)init{
    self = [super init];
    if (self) {
        cbCentralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
        
        scaning = false;
        
        devices = [[NSMutableArray alloc] init];
        
        connectCBMap = [[NSMutableDictionary alloc] init];
        
        disconnectFlagMap = [[NSMutableDictionary alloc] init];
    }
    return self;
}

- (void)centralManagerDidUpdateState:(CBCentralManager*)central{
    NSNotificationCenter* notify = NSNotificationCenter.defaultCenter;
    
    BOOL blePower = false;
    
    if (@available(iOS 10.0, *)) {  // 版本兼容
        if(central.state == CBManagerStatePoweredOn){  // 用户开启了蓝牙
            blePower = true;
        }else{
            blePower = false;
        }
    } else {
        if(central.state == CBCentralManagerStatePoweredOn){  // 用户开启了蓝牙
            blePower = true;
        }else{
            blePower = false;
        }
    }
    
    if(blePower){
        [notify postNotificationName:TBBLE_STATUSCHANGED object:[NSNumber numberWithBool:true]];
    } else {
        if(scaning){  // 如果处于扫描阶段，需要先停掉
            [self stopScan];
            if((scanCB != nil) && (scanCB.onScanFail != nil)){
                TBErrorCode* error = [[TBErrorCode alloc] init:TBOTHER msg:@"蓝牙被关闭"];
                scanCB.onScanFail(error);
            }
        }
        [notify postNotificationName:TBBLE_STATUSCHANGED object:[NSNumber numberWithBool:false]];
    }

}

/**
 获取蓝牙状态
 @return 蓝牙状态
 */
-(TBBLEStatus)getStatues{
    
    if (@available(iOS 10.0, *)) {  // 版本兼容
        switch (cbCentralManager.state) {
            case CBManagerStatePoweredOn:
                return TBBLE_OPENED;
            case CBManagerStateUnknown:
                return TBBLE_UNKNOW;
            default:
                return TBBLE_CLOSEED;
        }
    }
    
    switch (cbCentralManager.state) {
        case CBCentralManagerStatePoweredOn:
            return TBBLE_OPENED;
        case CBCentralManagerStateUnknown:
            return TBBLE_UNKNOW;
        default:
            return TBBLE_CLOSEED;
    }

}

/**
 开始扫描
 @param scanModeTmp 扫描模式
 @param uuidsTmp 过滤UUID,不需要则可以填nil
 @param scanCBTmp 扫描结果回调
 @param workTimeTmp 工作时间  工作模式为 扫描(工作时间)->停止扫描(休息时间)->扫描->停止扫描……
 @param sleepTimeTmp 休息时间
 @param workTimesTmp 工作次数 “扫描->停止扫描” 记一次   -1为无限次
 */
-(void)startScan:(TBBLEScanMode)scanModeTmp serviceUuids:(nullable NSArray<CBUUID *> *)uuidsTmp scanCB:(TBBLEScanCB*)scanCBTmp workTime:(int)workTimeTmp sleepTime:(int)sleepTimeTmp workTimes:(int)workTimesTmp{
    if([self getStatues] != TBBLE_OPENED){
        TBErrorCode* error = [[TBErrorCode alloc] init:TBOTHER msg:@"未开启蓝牙"];
        
        if(scanCBTmp.onScanFail != nil){
            scanCBTmp.onScanFail(error);
        }
        return;
    }
    
    if(scaning){  // 如果正在扫描
        TBErrorCode* error = [[TBErrorCode alloc] init:TBOTHER msg:@"已经开始扫描"];
        if(scanCBTmp.onScanFail != nil){
            scanCBTmp.onScanFail(error);
        }
        return;
    }
    
    scanMode = scanModeTmp;
    uuids = uuidsTmp;
    scanCB = scanCBTmp;
    workTime = workTimeTmp;
    sleepTime = sleepTimeTmp;
    workTimes = workTimesTmp;
    
    scaning = true;
    [self startScanWork];
    
}

- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *, id> *)advertisementData RSSI:(NSNumber *)RSSI{
    TBBLEDevice* device = [[TBBLEDevice alloc] init:peripheral advertisementData:advertisementData RSSI:RSSI];
    
    TBBLEDevice* savedDevice = [self findDevicesByUUID:device.peripheral.identifier.UUIDString];
    
    if(savedDevice != nil){  // 找到，就刷新一下信息
        [savedDevice refreshInfo:device];
    }else{
        savedDevice = device;
        [devices addObject:savedDevice];
    }
    
    if(scanCB.onScan != nil){
        scanCB.onScan(savedDevice);
    }
}

-(TBBLEDevice*)findDevicesByUUID:(NSString*)uuid{
    for (int i=0; i< devices.count; i++) {
        if([devices[i].peripheral.identifier.UUIDString isEqualToString:uuid]){
            return devices[i];
        }
    }

    return nil;
}
/**
 停止扫描
 */
-(void)stopScan{
    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(startScanWork) object:nil];  // 把延迟任务取消掉
    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(stopScanWork) object:nil];
    
    [cbCentralManager stopScan];
    scaning = false;
}

-(void)startScanWork{
    
    if(!scaning){ // 已经被取消了扫描的情况
        return;
    }
    [cbCentralManager scanForPeripheralsWithServices:uuids options:nil];
    
    [self runDelay:@selector(stopScanWork) withObject:nil afterDelay:workTime];
}

-(void)stopScanWork{
    if(scaning == false){ // 已经被取消了扫描的情况
        return;
    }
    [cbCentralManager stopScan];
    
    if(workTime > 0){  // 如果是负数的话，认为是无限次数
        workTimes--;
    }
    
    if(workTimes == 0){  // 扫描完了
        scaning = false;
        if(scanCB.onScanOver != nil){
            scanCB.onScanOver();
        }
        return;
    }
    
    [self runDelay:@selector(startScanWork) withObject:nil afterDelay:sleepTime];
    
}

/**
 连接设备
 @param device 需要连接的设备
 @param connectCB 连接回调
 */
-(void)connect:(TBBLEDevice*)device connectCB:(TBBLEConnectCB*)connectCB{
    if([self getStatues] != TBBLE_OPENED){
        TBErrorCode* error = [[TBErrorCode alloc] init:TBOTHER msg:@"未开启蓝牙"];
        if(connectCB.onConnect != nil){
            connectCB.onConnect(error);
        }
        return;
    }
    
    [connectCBMap setValue:connectCB forKey:device.peripheral.identifier.UUIDString];  // 把UUID和回调绑定起来
    [disconnectFlagMap setValue:[NSNumber numberWithBool:false] forKey:device.peripheral.identifier.UUIDString];  // 设置是否主动断开标志
    
    [cbCentralManager connectPeripheral:device.peripheral options:nil];
    
}

- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{
    TBBLEConnectCB* cb = (TBBLEConnectCB*)[connectCBMap valueForKey:peripheral.identifier.UUIDString];
    if(cb == nil){  // 该对象没有被绑定过
        return;
    }
    if(cb.onConnect != nil){  // 连接成功
        TBErrorCode* error = [[TBErrorCode alloc] init:TBSUCCESS msg:@""];
        cb.onConnect(error);
    }
}

- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error{
    TBBLEConnectCB* cb = (TBBLEConnectCB*)[connectCBMap valueForKey:peripheral.identifier.UUIDString];
    if(cb == nil){  // 该对象没有被绑定过
        return;
    }
    if(cb.onConnect != nil){  // 连接失败
        TBErrorCode* errorCode = [[TBErrorCode alloc] init:TBOTHER msg:error.description];
        cb.onConnect(errorCode);
    }
}

- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error{
    TBBLEConnectCB* cb = (TBBLEConnectCB*)[connectCBMap valueForKey:peripheral.identifier.UUIDString];
    if(cb == nil){  // 该对象没有被绑定过
        return;
    }
    
    [connectCBMap removeObjectForKey:peripheral.identifier.UUIDString];   // 把字典数据删除，以免无限增长
    
    BOOL manualDisconnect = false;
    NSNumber* disconnectFlag = (NSNumber*)[disconnectFlagMap valueForKey:peripheral.identifier.UUIDString];
    if(disconnectFlag != nil){
        manualDisconnect = disconnectFlag.boolValue;
    }
    
    [disconnectFlagMap removeObjectForKey:peripheral.identifier.UUIDString];  // 把字典数据删除，以免无限增长
    
    if(manualDisconnect){   // 主动调用断开的情况
        if(cb.onManualDisConnect != nil){
            TBErrorCode* errorCode = [[TBErrorCode alloc] init:TBSUCCESS msg:@""];
            cb.onManualDisConnect(errorCode);
        }
        return;
    }
    
    if(cb.onDisConnect != nil){  // 被动断开的情况
        TBErrorCode* errorCode = [[TBErrorCode alloc] init:TBSUCCESS msg:@""];
        cb.onDisConnect(errorCode);
    }
}

/**
 断开设备
 @param device 需要断开的设备
 */
-(void)disConnect:(TBBLEDevice*)device{
    [disconnectFlagMap setValue:[NSNumber numberWithBool:true] forKey:device.peripheral.identifier.UUIDString];  // 设置是否主动断开标志
    
    [cbCentralManager cancelPeripheralConnection:device.peripheral];
}

// 切换到主线程
-(void) runDelay:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay{
    if(![NSThread isMainThread]){
        dispatch_async(dispatch_get_main_queue(), ^{
            [self performSelector:aSelector withObject:anArgument afterDelay:delay];
        });
        
        return;
    }else{
        [self performSelector:aSelector withObject:anArgument afterDelay:delay];
    }
}

@end


// 扫描回调
@implementation TBBLEScanCB
@end

// 连接回调
@implementation TBBLEConnectCB
@end

